package JMH.day04;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 单线程：
 * Benchmark                                       Mode  Cnt  Score    Error  Units
 * JMH.day04.ReentrantLockVsSynchronized.testBase  avgt   10  0.002 ±  0.001  us/op
 * JMH.day04.ReentrantLockVsSynchronized.testLock  avgt   10  0.018 ±  0.001  us/op
 * JMH.day04.ReentrantLockVsSynchronized.testSync  avgt   10  0.004 ±  0.001  us/op
 *
 * Synchronized性能好。
 */
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Threads(1)
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
public class ReentrantLockVsSynchronized01 {

    private Test test;

    @Setup(Level.Iteration)
    public void setUp() {
        this.test = new Test();
    }

    @Benchmark
    public void testBase(Blackhole blackhole) {
        blackhole.consume(test.baseMethod());
    }

    @Benchmark
    public void testSync(Blackhole blackhole) {
        blackhole.consume(test.syncMethod());
    }

    @Benchmark
    public void testLock(Blackhole blackhole) {
        blackhole.consume(test.lockMethod());
    }

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(ReentrantLockVsSynchronized01.class.getSimpleName())
                .forks(1)
                .build();
        new Runner(options).run();
    }
}

class Test {

    private int x = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public int baseMethod() {
        return x;
    }

    public int lockMethod() {
        lock.lock();
        try {
            return x;
        } finally {
            lock.unlock();
        }
    }

    public int syncMethod() {
        synchronized (this) {
            return x;
        }
    }
}
